home *** CD-ROM | disk | FTP | other *** search
/ Aminet 37 / Aminet 37 (2000)(Schatztruhe)[!][Jun 2000].iso / Aminet / dev / lang / sofa.lha / sofa / smalleiffel / lib_std / input_stream.e < prev    next >
Text File  |  2000-03-25  |  15KB  |  506 lines

  1. -- This file is  free  software, which  comes  along  with  SmallEiffel. This
  2. -- software  is  distributed  in the hope that it will be useful, but WITHOUT 
  3. -- ANY  WARRANTY;  without  even  the  implied warranty of MERCHANTABILITY or
  4. -- FITNESS  FOR A PARTICULAR PURPOSE. You can modify it as you want, provided
  5. -- this header is kept unaltered, and a notification of the changes is added.
  6. -- You  are  allowed  to  redistribute  it and sell it, alone or as a part of 
  7. -- another product.
  8. --          Copyright (C) 1994-98 LORIA - UHP - CRIN - INRIA - FRANCE
  9. --            Dominique COLNET and Suzanne COLLIN - colnet@loria.fr 
  10. --                       http://SmallEiffel.loria.fr
  11. --
  12. deferred class INPUT_STREAM
  13.    --
  14.    -- This abstract class is the superclass of all classes 
  15.    -- representing an input stream of bytes. 
  16.    --
  17.  
  18. feature -- State of the stream :
  19.  
  20.    is_connected: BOOLEAN is
  21.          -- True when the corresponding stream is connected
  22.          -- to some physical input device.
  23.       deferred
  24.       end;
  25.  
  26.    end_of_input: BOOLEAN is
  27.          -- Has end-of-input been reached ?
  28.          -- True when the last character has been read.
  29.       require
  30.          is_connected
  31.       deferred
  32.       end;
  33.  
  34. feature -- To read one character at a time :
  35.  
  36.    read_character is
  37.          -- Read a character and assign it to `last_character'.
  38.       require
  39.          not end_of_input
  40.       deferred
  41.       ensure
  42.          not push_back_flag
  43.       end;
  44.  
  45.    last_character: CHARACTER is
  46.          -- Last character read with `read_character'.
  47.       require
  48.          is_connected
  49.       deferred
  50.       end;
  51.    
  52.    push_back_flag: BOOLEAN;
  53.          -- True in one char is already pushed back.
  54.  
  55.    unread_character is
  56.          -- Un-read the last character read.
  57.       require
  58.          not push_back_flag
  59.       deferred
  60.       ensure
  61.          push_back_flag
  62.       end;
  63.  
  64. feature -- Skipping separators :
  65.  
  66.    skip_separators is
  67.          -- Skip all separators (see `is_separator' of class CHARACTER) and 
  68.          -- make the first non-separator available in `last_character'. This 
  69.          -- non-separator character is pushed back into the stream (see 
  70.          -- `unread_character') to be available one more time (the next 
  71.          -- `read_character' will consider this non-separator). When 
  72.          -- `end_of_input' occurs, this process is automatically stopped.
  73.       do
  74.          from  
  75.          until
  76.             end_of_input or else not last_character.is_separator
  77.          loop
  78.             read_character;
  79.          end;
  80.          if not end_of_input and then not push_back_flag then
  81.             unread_character
  82.          end
  83.       end;
  84.    
  85.    skip_separators_using(separators:STRING) is
  86.          -- Same job as `skip_separators' using the `separators' set.
  87.       require 
  88.          separators /= void
  89.       do
  90.          from 
  91.          until
  92.             end_of_input or else 
  93.             not separators.has(last_character)
  94.          loop
  95.             read_character;
  96.          end;
  97.          if not end_of_input and then not push_back_flag then
  98.             unread_character
  99.          end
  100.       end;
  101.  
  102.    skip_remainder_of_line is
  103.          -- Skip all the remainder of the line including the end of 
  104.          -- line character itself.
  105.       local
  106.          stop: BOOLEAN;
  107.       do
  108.          from until stop
  109.          loop
  110.             if end_of_input then
  111.                stop := true;
  112.             else
  113.                inspect
  114.                   last_character
  115.                when '%N', '%R' then
  116.                   read_character;
  117.                   stop := true;
  118.                else 
  119.                   read_character;
  120.                end;
  121.             end;
  122.          end;
  123.       end;
  124.    
  125. feature -- To read one number at a time :
  126.    
  127.    read_integer is
  128.          -- Read an integer according to the Eiffel syntax.
  129.          -- Make result available in `last_integer'.
  130.          -- Heading separators are automatically skipped using 
  131.          -- `is_separator' of class CHARACTER.
  132.          -- Trailing separators are not skipped.
  133.       require
  134.          not end_of_input
  135.       local
  136.          state: INTEGER;
  137.          sign: BOOLEAN;
  138.          -- state = 0 : waiting sign or first digit.
  139.          -- state = 1 : sign read, waiting first digit.
  140.          -- state = 2 : in the number.
  141.          -- state = 3 : end state.
  142.          -- state = 4 : error state.
  143.       do
  144.          from
  145.          until
  146.             state > 2
  147.          loop
  148.             read_character;
  149.             inspect 
  150.                state
  151.             when 0 then
  152.                if last_character.is_separator then
  153.                elseif last_character.is_digit then
  154.                   last_integer := last_character.value;
  155.                   state := 2;
  156.                elseif last_character = '-' then
  157.                   sign := true;
  158.                   state := 1;
  159.                elseif last_character = '+' then
  160.                   state := 1;
  161.                else
  162.                   state := 4;
  163.                end;
  164.             when 1 then
  165.                if last_character.is_separator then
  166.                elseif last_character.is_digit then
  167.                   last_integer := last_character.value;
  168.                   state := 2;
  169.                else
  170.                   state := 4;
  171.                end;
  172.             else -- 2
  173.                if last_character.is_digit then
  174.                   last_integer := (last_integer * 10) + last_character.value;
  175.                else
  176.                   state := 3;
  177.                end;
  178.             end;
  179.             if end_of_input then
  180.                inspect 
  181.                   state
  182.                when 0 .. 1 then
  183.                   state := 4;
  184.                when 2 .. 3 then
  185.                   state := 3;
  186.                else -- 4
  187.                end;
  188.             end;
  189.          end;
  190.          if not end_of_input then
  191.             unread_character;
  192.          end;
  193.          debug
  194.             if state = 4 then
  195.                std_error.put_string("Error in INPUT_STREAM.read_integer.%N");
  196.                crash;
  197.             end;
  198.          end;
  199.          if sign then
  200.             last_integer := - last_integer;
  201.          end;
  202.       end;
  203.    
  204.    last_integer: INTEGER; 
  205.          -- Last integer read using `read_integer'.
  206.    
  207.    read_real is
  208.          -- Read a REAL and make the result available in `last_real'
  209.          -- and in `last_double'.
  210.          -- The integral part is available in `last_integer'.
  211.       require
  212.          not end_of_input
  213.       do
  214.          read_double;
  215.          last_real := last_double.to_real;
  216.       end;
  217.    
  218.    last_real: REAL; 
  219.          -- Last real read with `read_real'.
  220.    
  221.    read_double is
  222.          -- Read a DOUBLE and make the result available in `last_double'. 
  223.       require
  224.          not end_of_input
  225.       local
  226.          state: INTEGER;
  227.          sign: BOOLEAN;
  228.          -- state = 0 : waiting sign or first digit.
  229.          -- state = 1 : sign read, waiting first digit.
  230.          -- state = 2 : in the integral part.
  231.          -- state = 3 : in the fractional part.
  232.          -- state = 4 : end state.
  233.          -- state = 5 : error state.
  234.       do
  235.          from
  236.             last_string.clear
  237.          until
  238.             state >= 4
  239.          loop
  240.             read_character;
  241.             inspect 
  242.                state
  243.             when 0 then
  244.                if last_character.is_separator then
  245.                elseif last_character.is_digit then
  246.                   last_string.add_last(last_character)
  247.                   state := 2;
  248.                elseif last_character = '-' then
  249.                   sign := true;
  250.                   state := 1;
  251.                elseif last_character = '+' then
  252.                   state := 1;
  253.                elseif last_character = '.' then
  254.                   last_string.add_last(last_character)
  255.                   state := 3;
  256.                else
  257.                   state := 5;
  258.                end;
  259.             when 1 then
  260.                if last_character.is_separator then
  261.                elseif last_character.is_digit then
  262.                   last_string.add_last(last_character)
  263.                   state := 2;
  264.                else
  265.                   state := 5;
  266.                end;
  267.             when 2 then
  268.                if last_character.is_digit then
  269.                   last_string.add_last(last_character)
  270.                elseif last_character = '.' then
  271.                   last_string.add_last(last_character)
  272.                   state := 3;
  273.                else
  274.                   state := 4;
  275.                end;
  276.             else -- 3 
  277.                if last_character.is_digit then
  278.                   last_string.add_last(last_character)
  279.                else
  280.                   state := 4;
  281.                end;
  282.             end;
  283.             if end_of_input then
  284.                inspect
  285.                   state
  286.                when 2 .. 4 then
  287.                   state := 4;
  288.                else
  289.                   state := 5;
  290.                end;
  291.             end;
  292.          end;
  293.          if not end_of_input then
  294.             unread_character;
  295.          end;
  296.          debug
  297.             if state = 5 then
  298.                std_error.put_string("Error in STD_FILE.read_double.%N");
  299.                crash;
  300.             end;
  301.          end;
  302.          if last_string.count > 0 then
  303.             last_double := last_string.to_double
  304.          else
  305.             last_double := 0; -- NaN
  306.          end
  307.          if sign then
  308.             last_double := - last_double;
  309.          end;
  310.       end;
  311.    
  312.    last_double: DOUBLE;
  313.          -- Last double read with `read_double'.
  314.    
  315. feature -- To read one line or one word at a time :
  316.  
  317.    last_string: STRING is
  318.          -- Access to the unique common buffer to get for example the result 
  319.          -- computed by `read_line', `read_word', `newline', etc. This is a once 
  320.          -- function (the same common buffer is used for all streams).
  321.       once
  322.          !!Result.make(1024);
  323.       end;
  324.    
  325.    read_line is
  326.          -- Read a complete line ended by '%N' or `end_of_input'. Make the 
  327.          -- result available in `last_string' common buffer. The end of line 
  328.          -- character (usually '%N') is not added in the `last_string' buffer.
  329.       require
  330.          not end_of_input
  331.       do
  332.          last_string.clear;
  333.          read_line_in(last_string);
  334.       end;
  335.  
  336.    read_word is
  337.          -- Read a word using `is_separator' of class CHARACTER. Result is 
  338.          -- available in the `last_string' common buffer. Heading separators are 
  339.          -- automatically skipped. Trailing separators are not skipped 
  340.          -- (`last_character' is left on the first one). If `end_of_input' is 
  341.          -- encountered, Result can be the empty string.
  342.       require
  343.          not end_of_input
  344.       do
  345.          skip_separators;
  346.          if not end_of_input then
  347.             read_character;
  348.          end
  349.          from  
  350.             last_string.clear;
  351.          until
  352.             end_of_input or else
  353.             last_character.is_separator
  354.          loop
  355.             last_string.extend(last_character);
  356.             read_character;
  357.          end;
  358.       end;
  359.  
  360.    newline is
  361.          -- Consume input until newline ('%N') is found. Corresponding 
  362.          -- STRING is stored in `last_string' common buffer.
  363.       local
  364.          stop: BOOLEAN;
  365.       do
  366.          from  
  367.             last_string.clear;
  368.             stop := end_of_input;
  369.          until
  370.             stop
  371.          loop
  372.             read_character;
  373.             if end_of_input or else last_character = '%N' then
  374.                stop := true;
  375.             else
  376.                last_string.extend(last_character);
  377.             end;
  378.          end;
  379.       end;
  380.  
  381.    reach_and_skip(keyword: STRING) is
  382.          -- Try to skip enough characters in order to reach the `keyword' 
  383.          -- which is skipped too. If the `keyword' is not in the remainder of 
  384.          -- this stream, the process is stopped as soon  as `end_of_input' 
  385.          -- occurs. As for `skip_separators' the following character of the 
  386.          -- `keyword' is available in `last_character' and not yet read.
  387.       require
  388.          not keyword.is_empty
  389.       local
  390.          stop: BOOLEAN;
  391.          i: INTEGER;
  392.          first: CHARACTER;
  393.       do
  394.          from
  395.             last_string.clear;
  396.             first := keyword.first;
  397.          until
  398.             end_of_input or else stop
  399.          loop
  400.             -- Reach the first character of the `keyword':
  401.             from
  402.                i := 2;
  403.             until
  404.                i > last_string.count or else last_string.item(i) = first
  405.             loop
  406.                i := i + 1;
  407.             end
  408.             if i <= last_string.count then    
  409.                last_string.remove_first(i - 1);
  410.             else
  411.                last_string.clear;
  412.                from
  413.                   if not end_of_input then
  414.                      read_character;
  415.                   end
  416.                until
  417.                   end_of_input or else last_character = first
  418.                loop
  419.                   read_character
  420.                end
  421.                last_string.extend(last_character);
  422.             end
  423.             check
  424.                not end_of_input implies last_string.item(1) = first;
  425.                last_string.count <= keyword.count;
  426.             end
  427.             -- Now we need as many characters as in `keyword':
  428.             from
  429.             until
  430.                end_of_input or else last_string.count = keyword.count
  431.             loop
  432.                read_character
  433.                last_string.extend(last_character);
  434.             end
  435.             stop := last_string.is_equal(keyword);
  436.          end
  437.          if not end_of_input then
  438.             read_character;
  439.             unread_character;
  440.          end;
  441.       ensure
  442.          not end_of_input implies last_string.is_equal(keyword)
  443.       end
  444.  
  445. feature -- Other features :
  446.  
  447.    read_line_in(buffer: STRING) is
  448.          -- Same jobs as `read_line' but storage is directly done in `buffer'.
  449.          --
  450.       require
  451.          not end_of_input;
  452.      buffer /= Void
  453.       deferred
  454.       end;
  455.  
  456.    read_word_using(separators: STRING) is
  457.          -- Same jobs as `read_word' using `separators'.
  458.       require 
  459.          not end_of_input;
  460.          separators /= void
  461.       do
  462.          skip_separators_using(separators);
  463.          if not end_of_input then
  464.             read_character;
  465.          end
  466.          from  
  467.             last_string.clear;
  468.          until
  469.             end_of_input or else
  470.             separators.has(last_character)
  471.          loop
  472.             last_string.extend(last_character);
  473.             read_character;
  474.          end;
  475.       end;
  476.  
  477.    read_tail_in(str: STRING) is
  478.          -- Read all remaining character of the file in `str'.
  479.       require
  480.          str /= Void
  481.       do
  482.          from
  483.          until
  484.             end_of_input
  485.          loop
  486.             read_character;
  487.             if not end_of_input then
  488.                str.extend(last_character);
  489.             end;
  490.          end;
  491.       ensure
  492.          end_of_input
  493.       end;
  494.  
  495. feature {NONE}
  496.  
  497.    eof_code: INTEGER is 
  498.       external "SmallEiffel"
  499.       end;
  500.  
  501.    read_byte(stream_pointer : POINTER): INTEGER is
  502.       external "SmallEiffel"
  503.       end;
  504.  
  505. end -- INPUT_STREAM
  506.